<template>
    <el-card>
      <el-row :gutter="6">
        <el-col :span="10">
          <el-card class="box-card">
            <template #header>
              <div class="card-header justify-between">
                <div class="text">角色列表</div>
                <div>
                  <el-input
                    v-model="roleQuery.name"
                    placeholder="请输入角色名称"
                    clearable
                    size="small"
                    @keyup.enter="getRoleList"
                    width="100"
                  />
                  <el-button
                    type="primary"
                    size="small"
                    icon="Search"
                    @click="getRoleList"
                  >
                    筛选
                  </el-button>
                </div>
              </div>
            </template>
            <el-table
              row-class-name="table-row-selectable"
              v-loading="roleLoading"
              highlight-current-row
              :data="roleList"
              style="height: 59vh; width: 50vw"
              @row-click="handleRoleListClick"
            >
              <el-table-column prop="name" label="角色名" />
              <el-table-column prop="totalPeople" label="分配用户" />
              <el-table-column prop="createTime" label="创建时间" />
            </el-table>
            <!-- 分页组件 -->
            <pagination
              small
              v-show="roleTotal > 0"
              :total="roleTotal"
              v-model:page="roleQuery.pageNum"
              v-model:limit="roleQuery.pageSize"
              :layout="'prev, pager, next'"
              @pagination="getRoleList"
            />
          </el-card>
        </el-col>
  
        <el-col :span="12">
          <el-card class="box-card">
            <template #header>
              <div class="card-header justify-between">
                <div class="text">权限树</div>
                <div v-if="permissionTree.length > 0">
                  <el-button
                    type="info"
                    plain
                    icon="Sort"
                    size="small"
                    @click="handleToggleExpandAll"
                  >
                    展开/折叠
                  </el-button>
                  <el-button
                    type="primary"
                    @click="handleSavePermission"
                    size="small"
                  >
                    保存
                  </el-button>
                  <el-button @click="handleReset" size="small">重置</el-button>
                </div>
              </div>
            </template>
  
            <el-scrollbar style="height: 70vh">
              <el-tree
                v-loading="isLoading"
                :data="permissionTree"
                show-checkbox
                node-key="id"
                :default-expand-all="false"
                :expand-on-click-node="true"
                :default-checked-keys="childPermissionIds"
                empty-text="暂无数据"
                ref="treeRef"
                @check="nodeClick"
              >
                <template #default="{ node, data }">
                  <span class="custom-tree-node">
                    <span>{{ node.label }}</span>
                    <span class="setting">
                      <el-tooltip
                        content="更新角色可视字段"
                        placement="top"
                        :enterable="false"
                      >
                        <el-button
                          link
                          type="primary"
                          icon="View"
                          v-show="data.returnModelId && data.isChecked === true"
                          @click="viewSetting(data)"
                        ></el-button>
                      </el-tooltip>
                      <el-tooltip
                        content="更新角色可改字段"
                        placement="top"
                        :enterable="false"
                      >
                        <el-button
                          link
                          type="primary"
                          icon="Edit"
                          v-show="data.requestModelId && data.isChecked === true"
                          @click="updateSetting(data)"
                        ></el-button>
                      </el-tooltip>
                    </span>
                  </span>
                </template>
              </el-tree>
            </el-scrollbar>
          </el-card>
        </el-col>
      </el-row>
      <!--      <el-tabs-->
      <!--        tab-position="left"-->
      <!--        style="height: 100vh"-->
      <!--        class="demo-tabs"-->
      <!--        type="border-card"-->
      <!--        @tab-click="tabChange"-->
      <!--      >-->
      <!--        <el-scrollbar style="height: 95vh">-->
      <!--          <el-tab-pane-->
      <!--            :name="(item as any).id"-->
      <!--            :label="(item as any).name"-->
      <!--            v-for="(item, index) in roleList"-->
      <!--            :key="index"-->
      <!--          >-->
      <!--            <el-tree-->
      <!--              v-loading="isLoading"-->
      <!--              :data="permissionTree"-->
      <!--              show-checkbox-->
      <!--              node-key="id"-->
      <!--              :default-expand-all="false"-->
      <!--              :expand-on-click-node="true"-->
      <!--              :default-checked-keys="childPermissionIds"-->
      <!--              empty-text="暂无数据"-->
      <!--              ref="treeRef"-->
      <!--              @check="nodeClick"-->
      <!--            >-->
      <!--              <template #default="{ node, data }">-->
      <!--                <span class="custom-tree-node">-->
      <!--                  <span>{{ node.label }}</span>-->
      <!--                  <span class="setting">-->
      <!--                    <el-tooltip-->
      <!--                      content="更新角色可视字段"-->
      <!--                      placement="top"-->
      <!--                      :enterable="false"-->
      <!--                    >-->
      <!--                      <el-button-->
      <!--                        link-->
      <!--                        type="primary"-->
      <!--                        icon="View"-->
      <!--                        v-show="data.returnModelId && data.isChecked === true"-->
      <!--                        @click="viewSetting(data)"-->
      <!--                      ></el-button>-->
      <!--                    </el-tooltip>-->
      <!--                    <el-tooltip-->
      <!--                      content="更新角色可改字段"-->
      <!--                      placement="top"-->
      <!--                      :enterable="false"-->
      <!--                    >-->
      <!--                      <el-button-->
      <!--                        link-->
      <!--                        type="primary"-->
      <!--                        icon="Edit"-->
      <!--                        v-show="data.requestModelId && data.isChecked === true"-->
      <!--                        @click="updateSetting(data)"-->
      <!--                      ></el-button>-->
      <!--                    </el-tooltip>-->
      <!--                  </span>-->
      <!--                </span>-->
      <!--              </template>-->
      <!--            </el-tree>-->
      <!--            <div style="margin: 10px 0 0 10vw">-->
      <!--              <el-button-->
      <!--                type="primary"-->
      <!--                @click="handleSavePermission"-->
      <!--                size="small"-->
      <!--              >-->
      <!--                保存-->
      <!--              </el-button>-->
      <!--              <el-button @click="handleReset" size="small">取消</el-button>-->
      <!--            </div>-->
      <!--          </el-tab-pane>-->
      <!--        </el-scrollbar>-->
      <!--      </el-tabs>-->
    </el-card>
  
    <!-- 设置字段对话框 -->
    <el-dialog
      v-model="dialogStatus.isVisible"
      :title="dialogStatus.title"
      width="40%"
      center
      append-to-body
      :show-close="false"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <el-checkbox
        v-model="checkAll"
        :indeterminate="isIndeterminate"
        @change="handleCheckAllChange"
      >
        全选
      </el-checkbox>
      <el-checkbox-group v-model="currentFields">
        <el-checkbox
          v-for="item in fields"
          :key="(item as any).id"
          :label="(item as any).name"
          @change="handleCheckedCitiesChange"
          border
        >
          {{ (item as any).displayName }}
        </el-checkbox>
      </el-checkbox-group>
      <div style="margin: 20px 0 0 24vw">
        <el-button
          type="primary"
          icon="Search"
          @click="innerDialogSubmit"
          v-hasPermi="['system:role:edit']"
        >
          保存
        </el-button>
        <el-button icon="Search" @click="handleCloseDialog">取消</el-button>
      </div>
    </el-dialog>
  </template>
  
  <script setup lang="ts">
  import {
    getFields as getFieldsApi,
    getPermissionTree as getPermissionTreeApi,
    getRoleList as getRoleListApi,
    getRolePermission as getRolePermissionApi,
    getSavedFields as getSavedFieldsApi,
    savePermission as savePermissionApi,
  } from "@/service/api/system/rolePermission";
  import to from "await-to-js";
  import {
    PermissionNode,
    SysFieldVo,
    SysModelVo,
    SysRoleVo,
  } from "@/service/api/system/rolePermission/types.ts";
  import { BasePageResponse, BaseResponse } from "@/service/api/type.ts";
  import { ElTable } from "element-plus";
  import Pagination from "@/components/Pagination/index.vue";
  import {removeButtonFocus} from "@/utils/focus.tsx";
  
  // dialog
  const initDialogStatus = {
    isVisible: false,
    title: "",
  };
  /**
   * 角色查询参数
   */
  const roleQuery = ref({
    name: "",
    superAdmin: false,
    pageSize: 10,
    pageNum: 1,
    orderByColumn: "createTime",
    orderType: "desc",
  });
  
  const roleLoading = ref<boolean>(false);
  const permissionLoading = ref<boolean>(false);
  const isExpandAll = ref(false);
  const treeRef = ref(ElTable);
  
  // 页面数据
  const pageData = reactive({
    permissionTree: <PermissionNode[]>[],
    roleTotal: 0,
    roleList: <SysRoleVo[]>[],
    filterPermissionIds: [],
    dialogStatus: { ...initDialogStatus },
  });
  
  const { permissionTree, roleTotal, roleList, dialogStatus } = toRefs(pageData);
  const isLoading = ref(false);
  // 当前角色id
  const currentRoleId = ref();
  // 是否全选
  const checkAll = ref(false);
  // 是否半选
  const isIndeterminate = ref(false);
  // 已勾选数组
  const finalNodes: any = ref([]);
  // 所有字段
  const fields = ref<SysFieldVo[]>([]);
  // 后台已勾选的子节点
  // 角色已勾选的权限
  const childPermissionIds = ref<string[]>([]);
  const permissionIds = ref<string[]>([]);
  // 当前勾选的字段数组
  const currentFields = ref<string[]>([]);
  // 当前点击的节点id
  const currentPermissionId = ref("");
  
  /**
   * 选中用户列表
   */
  const handleRoleListClick = async (row: any) => {
    permissionLoading.value = true;
    currentRoleId.value = row.id;
  
    getCurrentRolePermission();
  };
  
  /**
   * 获取当前角色权限信息
   */
  const getCurrentRolePermission = async(): Promise<boolean> => {
    const [err, res] = await to<BaseResponse<SysRoleVo>, any>(
        getRolePermissionApi(currentRoleId.value),
    );
    if (!err) {
      console.log(res?.data);
      // 按钮和接口选中的id列表（只包含子节点）
      childPermissionIds.value = res?.data?.sonIdList ?? [];
      // 所有选中的权限id列表（包含父节点）
      permissionIds.value = res?.data?.permissionIds ?? [];
      isLoading.value = false;
      return await getPermissionTree();
    }
  
    isLoading.value = false;
    return false;
  }
  
  /**
   * 获取角色列表，不泄漏异常
   */
  const getRoleList = async (): Promise<boolean> => {
    const [err, res] = await to<BasePageResponse<SysRoleVo>, any>(
      getRoleListApi(roleQuery.value),
    );
    if (!err) {
      roleList.value = res?.rows ?? [];
      roleTotal.value = Number(res?.total ?? 0);
      console.log(roleList.value);
      return true;
    }
    return false;
  };
  
  /**
   * 获取权限树（无勾选状态），不泄露异常
   */
  const getPermissionTree = async (): Promise<boolean> => {
    const [err, res] = await to<BaseResponse<PermissionNode[]>, any>(
      getPermissionTreeApi(),
    );
    if (!err) {
      permissionTree.value = res?.data ?? [];
      console.log(permissionTree.value);
      setDefaultChecked(permissionTree.value);
      return true;
    }
    return false;
    // const ids = getRootIds(permissionTree.value);
    // console.log(ids.length);
  };
  
  /**
   * 初次渲染设置选中状态
   * @param treeArr
   */
  const setDefaultChecked = (treeArr: any) => {
    for (let i = 0; i < treeArr.length; i++) {
      let node = treeArr[i];
      // 遍历每个节点并且设置为已勾选
      node.isChecked = permissionIds.value.some((item) => item === node.id);
      if (node.children && node.children.length > 0) {
        setDefaultChecked(node.children);
      }
    }
  };
  
  /**
   * 遍历permissionTree,设置已勾选的为true
   * @param treeArr
   */
  const setDynamicChecked = (treeArr: any) => {
    for (let i = 0; i < treeArr.length; i++) {
      const node = treeArr[i];
      // 找到已勾选列表是否有
      // 有就勾上 没有就不勾
      node.isChecked = checkedNodes.value.some((item: any) => {
        return item.id === node.id;
      });
      if (node.children && node.children.length > 0) {
        setDynamicChecked(node.children); // 递归调用，处理每个子节点
      }
    }
  };
  
  /**
   * 在tree中找到该节点并赋值
   * @param treeArr
   * @param permissionId
   */
  const setEditFields = (treeArr: any, permissionId: string) => {
    for (let i = 0; i < treeArr.length; i++) {
      let node = treeArr[i];
      if (node.id === permissionId) {
        node.editableFields.fields = currentFields.value;
      }
      if (node.children && node.children.length > 0) {
        setEditFields(node.children, permissionId); // 递归调用，处理每个子节点
      }
    }
  };
  /**
   * 在tree中找到该节点并赋值
   * @param treeArr
   * @param permissionId
   */
  const setVisFields = (treeArr: any, permissionId: string) => {
    for (let i = 0; i < treeArr.length; i++) {
      let node = treeArr[i];
      if (node.id === permissionId) {
        node.visibleFields.fields = currentFields.value;
      }
      if (node.children && node.children.length > 0) {
        setVisFields(node.children, permissionId); // 递归调用，处理每个子节点
      }
    }
  };
  
  /**
   * 遍历拿到树形节点中所有选中的节点
   * @param treeArr
   */
  const getCheckedNodes = (treeArr: any) => {
    for (let i = 0; i < treeArr.length; i++) {
      let node = treeArr[i];
      if (node.isChecked) {
        console.log(node);
        node.permissionId = node.id;
        finalNodes.value.push(node as object);
      } else {
        node.isChecked = false;
      }
      if (node.children && node.children.length > 0) {
        getCheckedNodes(node.children); // 递归调用，处理每个子节点
      }
    }
  };
  
  // 所有已选择的node
  const checkedNodes: any = ref([]);
  
  /**
   * 复选框被点击
   * @param node
   * @param status
   */
  const nodeClick = async (node: any, status: any) => {
    // 保存已勾选的节点
    console.log(node);
  
    checkedNodes.value = [
      ...JSON.parse(JSON.stringify(status.checkedNodes)),
      ...JSON.parse(JSON.stringify(status.halfCheckedNodes)),
    ];
    console.log(permissionTree.value, checkedNodes.value);
  
    setDynamicChecked(permissionTree.value);
  };
  
  /**
   * 处理权限保存
   */
  const handleSavePermission = async () => {
    const [err, confirm] = await to<string, string>(
      ElMessageBox.confirm("是否确定要保存所有权限?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }),
    );
    if (err === "cancel") {
      ElMessage({
        type: "info",
        message: "取消保存",
      });
    } else if (confirm === "confirm") {
      getCheckedNodes(permissionTree.value);
      const [err2, res2] = await to<BaseResponse<any>, any>(
        savePermissionApi(currentRoleId.value, finalNodes.value),
      );
      if (!err2) {
        console.log(res2);
        ElMessage({
          type: "success",
          message: "保存成功",
        });
      } else {
        console.log(err2);
        console.log(finalNodes.value, permissionTree.value);
      }
      finalNodes.value = [];
      // 刷新
      getCurrentRolePermission();
    }
  };
  
  /**
   * 处理展开折叠
   */
  const handleToggleExpandAll = (event: MouseEvent) => {
    isExpandAll.value = !isExpandAll.value;
    let nodes = treeRef.value.store.nodesMap;
    for (const node in nodes) {
      nodes[node].expanded = isExpandAll.value;
    }
    removeButtonFocus(event);
  };
  
  /**
   * 处理重置按钮
   */
  const handleReset = async () => {
    const [err, confirm] = await to<string, string>(
      ElMessageBox.confirm("是否删除所有操作回到初始状态?", "提示", {
        confirmButtonText: "是",
        cancelButtonText: "否",
        type: "warning",
      }),
    );
    if (err === "cancel") {
      ElMessage({
        type: "info",
        message: "取消重置，所有勾选依然处于未保存状态",
      });
    } else if (confirm === "confirm") {
      const response = await getCurrentRolePermission();
      if (response) {
        ElMessage({
          type: "success",
          message: "重置成功",
        });
      }
    }
  };
  
  /**
   * 设置可视字段
   * @param data
   */
  const viewSetting = async (data: any) => {
    // 获取该节点所有字段
    currentPermissionId.value = data.id;
    const [err, res] = await to<BaseResponse<SysModelVo>, any>(
      getFieldsApi(data.returnModelId),
    );
    console.log(res);
    if (!err) {
      fields.value = res?.data?.fields ?? [];
      // 要添加的临时参数
      const visibleFields = {
        modelId: data.returnModelId,
        fields: [],
      };
  
      if (data.visibleFields) {
        // 如果已经有了则说明设置过
        currentFields.value = data.visibleFields.fields;
      } else {
        // 给节点加上这个字段
        data.visibleFields = visibleFields;
        // 发请求获取后台已勾选的
        // 获取已勾选的BO
        const currentQueryData = {
          roleId: currentRoleId.value,
          permissionId: data.id,
        };
        const [err, res2] = await to<BaseResponse<SysModelVo>, any>(
          getSavedFieldsApi(currentQueryData),
        );
        if (!err) {
          console.log(res2?.data);
          currentFields.value = res2?.data?.visibleFields?.fields ?? [];
          // 将后台给的数据放入节点
          data.visibleFields.fields = currentFields.value;
        }
      }
  
      // 已选字段
      checkAll.value = currentFields.value.length === fields.value.length;
      isIndeterminate.value =
        currentFields.value.length > 0 &&
        currentFields.value.length < fields.value.length;
      dialogStatus.value.isVisible = true;
      dialogStatus.value.title = "修改可视字段";
    }
  };
  
  /**
   * 设置可改字段
   * @param data
   */
  const updateSetting = async (data: any) => {
    // 获取该节点所有字段
    console.log(permissionTree.value);
    currentPermissionId.value = data.id;
    const [err, res] = await to<BaseResponse<SysModelVo>, any>(
      getFieldsApi(data.requestModelId),
    );
    if (!err) {
      console.log(res);
      fields.value = res?.data?.fields ?? [];
      console.log(fields.value);
  
      // 要添加的临时参数
      const editableFields = {
        modelId: data.requestModelId,
        fields: [],
      };
  
      if (data.editableFields) {
        // 如果已经有了则说明设置过
        currentFields.value = data.editableFields.fields;
      } else {
        // 给节点加上这个字段
        data.editableFields = editableFields;
        // 获取已勾选的BO
  
        const currentQueryData = {
          roleId: currentRoleId.value,
          permissionId: data.id,
        };
        // 发请求获取后台已勾选的
  
        const [err, res2] = await to<BaseResponse<SysModelVo>, any>(
          getSavedFieldsApi(currentQueryData),
        );
        if (!err) {
          console.log(res2?.data);
          currentFields.value = res2?.data?.editableFields?.fields ?? [];
          // 将后台给的数据放入节点
          data.editableFields.fields = currentFields.value;
        }
      }
    }
  
    // 已选字段
    checkAll.value = currentFields.value.length === fields.value.length;
    isIndeterminate.value =
      currentFields.value.length > 0 &&
      currentFields.value.length < fields.value.length;
    dialogStatus.value.isVisible = true;
    dialogStatus.value.title = "修改可改字段";
  };
  
  /**
   * 全选按钮
   * @param val
   */
  const handleCheckAllChange = (val: boolean) => {
    console.log(val);
    const tempFields = val ? fields.value : [];
    isIndeterminate.value = false;
    // 过滤出只有name字段的数组
    currentFields.value = tempFields.map((item: any) => item.name);
    console.log(currentFields.value);
  };
  
  /**
   * 选中按钮
   */
  const handleCheckedCitiesChange = () => {
    console.log(permissionTree.value);
    checkAll.value = currentFields.value.length === fields.value.length;
    isIndeterminate.value =
      currentFields.value.length > 0 &&
      currentFields.value.length < fields.value.length;
  };
  
  /**
   * 对话框保存
   */
  const innerDialogSubmit = async () => {
    // 保存勾选的字段
    console.log(permissionTree.value);
    if (dialogStatus.value.title === "修改可视字段") {
      setVisFields(permissionTree.value, currentPermissionId.value);
    } else {
      setEditFields(permissionTree.value, currentPermissionId.value);
    }
    dialogStatus.value = Object.assign({}, initDialogStatus);
  };
  
  /**
   * 关闭对话框
   */
  const handleCloseDialog = () => {
    dialogStatus.value = Object.assign({}, initDialogStatus);
  };
  
  onMounted(() => {
    getPermissionTree();
    getRoleList();
  });
  </script>
  
  <style scoped>
  .card-header {
    display: flex;
  
    .text {
      width: 150px;
      /* background-color: aqua; */
    }
  
    .el-input {
      margin: 0 5px 0 0;
      width: 200px;
    }
  }
  
  .el-tabs--right .el-tabs__content,
  .el-tabs--left .el-tabs__content {
    height: 100%;
  }
  
  .custom-tree-node {
    flex: 1;
    /* display: flex; */
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
  
    .setting {
      margin: 0 0 10px 10px;
    }
  }
  </style>
  